import * as fs from 'fs';
import * as path from 'path';
import {isExist, markPathSplit, pathResolve, pathSplit} from "../unit";

/**
 * 该类自身主要负责目录方面的创建与删除
 * */
export default class FileStrategy{

    constructor(){}

    /*未测试*/
    static rmDirectorySync(_path:any, index:any){
        if(_path){
            FileStrategy.rmDirectorySync(_path, ++index);
        }
    }

    /*未测试*/
    static rmdir(_path:any){
        let index = 1;
        _path = pathResolve(_path);
        _path = markPathSplit(_path);
        for(let i=1,length=_path.length;i<length;i++){
            _path[i] = _path[(i-1)] + path.sep + _path[i]
        }
        FileStrategy.rmDirectorySync(_path, index);
    }

    /**
     * path: 创建的文件夹路径
     * 使用相对路径'./'
     * @return {string[]}
     * */
    static async createDirectory(_path:string):Promise<string[]>{
        let index = 1;

        return await FileStrategy.markDirectorySync(pathSplit(_path),index);
    }

    private static markDirectorySync(path: string[], index:number):string[]{
        if(path.length <= index){
            return path;
        }
        if(!isExist(path[index]))fs.mkdirSync(path[index]);
        return FileStrategy.markDirectorySync(path, ++index);
    }

    static async writeFile(filePath:string, fileName:string, data:string, callback?:any){
        await FileStrategy.createDirectory(filePath);
        return FileStrategy.write(FileStrategy.pathSplice(filePath,fileName), data, callback);
    }

    /**
     * 将文件路径与文件名合并成一条路径
     * 使用相对路径'./'
     * */
    static pathSplice(filePath:string, fileName:string):string{
        const _filePath = path.resolve(filePath);
        return _filePath+path.sep+fileName
    }

    /**
     * 支持相对路径
     * @param filePath {string} 使用相对路径'./'
     * Function: 测试目录是否存在
     * fail: false
     * done: true
     * */
    static isDirectory(filePath:string):boolean{
        const result = pathSplit(filePath);
        let r:boolean = true;
        result.forEach((val)=>{
            if(!isExist(val)){
                r = false;
            }
        });
        return r;
    }

    private static stringToUnit8Array(text:string){
        // let _textArray = text.split('');
        // utf8中文字符占用3字节
        // const BYTE_LENGTH = 3;
        // let buf = Buffer.alloc(_textArray.length * BYTE_LENGTH);
        let buf = Buffer.from(text);
        buf.write(text);
        return buf;
    }

    /**
     * @param resolve
     * @param reject
     * @param _data 编码后的数据
     * */
    private static writeDefaultCallback(resolve, reject, _data){
        return function cb(err){
            if(err){
                reject(err);
            }
            resolve(_data);
        }
    }

    /**
     * @param fileName {string} 文件路径与文件名:./test1/a.txt
     * @param data 要写入到文件中的数据
     * @param callback
     * */
    static write(fileName:string, data:string, callback=FileStrategy.writeDefaultCallback){
        const _fileName = path.resolve(fileName);
        let _data:Buffer;
        if(!Buffer.isBuffer(data)){
            _data = this.stringToUnit8Array(data);
        }
        return new Promise(
            (resolve, reject)=>{
                return fs.writeFile(_fileName, _data, callback.call(null, resolve, reject, _data));
            });
    }

    /**
     * 可以重命名文件夹名与文件名
     * */
    static rename(oldPath:string, newPath:string){
        const _oldPath = path.resolve(oldPath);
        const _newPath = path.resolve(newPath);
        return new Promise((resolve, reject)=>{
            fs.renameSync(_oldPath, _newPath);
            resolve(_newPath);
        })
    }

    static async readFile(filePath:string, fileName:string, isString=false):Promise<Buffer|string>{
        if(!FileStrategy.isDirectory(filePath)){
            throw '没有找到文件夹';
        }
        const _filePath = FileStrategy.pathSplice(path.resolve(filePath),fileName);

        return FileStrategy.read(_filePath, isString);
    }


    /**
     * @param filePath 文件路径
     * @param isString false返回buffer,true返回字符串
     * 根据fs.lstatSync返回的参数判断该返回成功还是失败的函数
     * */
    static read(filePath:string, isString:boolean):Promise<Buffer|string>{
        function ok(resolve, reject){
            fs.readFile(filePath,(err, data)=>{
                if(err){
                    reject(err);
                }
                if(isString){
                    resolve(data);
                }else{
                    resolve(data.toString());
                }
            })
        }

        function failure(){
            return new Promise((resolve,reject)=>{
                reject('read is error.');
            })
        }

        return new Promise((resolve,reject)=>{
            if(fs.lstatSync(filePath)){return ok(resolve,reject)}else{return failure();}
        })
    }

}